#include <mc/sky.h>
#include <mc/mcwidget.h>
#include <opengl/texture.h>
#include <iostream>

namespace mc
{

opengl::Shader Sky::shader;

float Sky::vertices[] =  {
    // positions          
    -1.0f,  1.0f, -1.0f,
    -1.0f, -1.0f, -1.0f,
     1.0f, -1.0f, -1.0f,
     1.0f, -1.0f, -1.0f,
     1.0f,  1.0f, -1.0f,
    -1.0f,  1.0f, -1.0f,

    -1.0f, -1.0f,  1.0f,
    -1.0f, -1.0f, -1.0f,
    -1.0f,  1.0f, -1.0f,
    -1.0f,  1.0f, -1.0f,
    -1.0f,  1.0f,  1.0f,
    -1.0f, -1.0f,  1.0f,

     1.0f, -1.0f, -1.0f,
     1.0f, -1.0f,  1.0f,
     1.0f,  1.0f,  1.0f,
     1.0f,  1.0f,  1.0f,
     1.0f,  1.0f, -1.0f,
     1.0f, -1.0f, -1.0f,

    -1.0f, -1.0f,  1.0f,
    -1.0f,  1.0f,  1.0f,
     1.0f,  1.0f,  1.0f,
     1.0f,  1.0f,  1.0f,
     1.0f, -1.0f,  1.0f,
    -1.0f, -1.0f,  1.0f,

    -1.0f,  1.0f, -1.0f,
     1.0f,  1.0f, -1.0f,
     1.0f,  1.0f,  1.0f,
     1.0f,  1.0f,  1.0f,
    -1.0f,  1.0f,  1.0f,
    -1.0f,  1.0f, -1.0f,

    -1.0f, -1.0f, -1.0f,
    -1.0f, -1.0f,  1.0f,
     1.0f, -1.0f, -1.0f,
     1.0f, -1.0f, -1.0f,
    -1.0f, -1.0f,  1.0f,
     1.0f, -1.0f,  1.0f
};

Sky::Sky(const std::vector<std::string>& faces) : 
    _texture{nullptr}, _vao{}, _vbo{}
{
    this->_vao.bind();
    this->_vbo.bind();
    this->_vbo.setBufferData(sizeof(Sky::vertices), Sky::vertices, GL_STATIC_DRAW);
    this->_vao.setVertexAttribPointer(0, 3, GL_FLOAT, 3 * sizeof(float), (void*)0);
    this->_texture = opengl::Texture::loadCubemapTexture(faces);
}

Sky::~Sky() noexcept
{
#ifdef DEBUG
    std::cout << "free sky(vao, vbo)\n";
#endif
    this->_vao.free();
    this->_vbo.free();
}

void Sky::draw()
{
    this->_vao.bind();
    Sky::shader.setInt("skybox", this->_texture->index());
    glDepthFunc(GL_LEQUAL);  
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glDepthFunc(GL_LESS); 
}

void Sky::createShader(const glm::mat4& projection)
{
    Sky::shader = opengl::Shader("./resources/shaders/cubemap.vert", "./resources/shaders/cubemap.frag");
    Sky::shader.bind();
    Sky::shader.setMat4("projection", projection);
    Sky::shader.unbind();
}

void Sky::prepareRender(const glm::mat4& view)
{
    Sky::shader.bind();
    Sky::shader.setMat4("view", view);
}

}